using System;
using System.Collections.Generic;
using System.Linq;
using StardewModdingAPI.Enums;
using StardewValley;

namespace StardewModdingAPI.Framework.StateTracking.Snapshots;

/// <summary>A frozen snapshot of a tracked player.</summary>
internal class PlayerSnapshot
{
    /*********
    ** Fields
    *********/
    /// <summary>An empty item list diff.</summary>
    private readonly SnapshotItemListDiff EmptyItemListDiff = new([], [], []);


    /*********
    ** Accessors
    *********/
    /// <summary>The player being tracked.</summary>
    public Farmer Player { get; }

    /// <summary>The player's current location.</summary>
    public SnapshotDiff<GameLocation> Location { get; } = new();

    /// <summary>Tracks changes to the player's skill levels.</summary>
    public IDictionary<SkillType, SnapshotDiff<int>> Skills { get; } =
        Enum
            .GetValues(typeof(SkillType))
            .Cast<SkillType>()
            .ToDictionary(skill => skill, _ => new SnapshotDiff<int>());

    /// <summary>Get a list of inventory changes.</summary>
    public SnapshotItemListDiff Inventory { get; private set; }


    /*********
    ** Public methods
    *********/
    /// <summary>Construct an instance.</summary>
    /// <param name="player">The player being tracked.</param>
    public PlayerSnapshot(Farmer player)
    {
        this.Player = player;
        this.Inventory = this.EmptyItemListDiff;
    }

    /// <summary>Update the tracked values.</summary>
    /// <param name="watcher">The player watcher to snapshot.</param>
    public void Update(PlayerTracker watcher)
    {
        this.Location.Update(watcher.LocationWatcher!);
        foreach ((SkillType skill, var value) in this.Skills)
            value.Update(watcher.SkillWatchers[skill]);

        this.Inventory = watcher.TryGetInventoryChanges(out SnapshotItemListDiff? itemChanges)
            ? itemChanges
            : this.EmptyItemListDiff;
    }
}
